package log

import (
	"fmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

type ZapOption func(options *ZapLogger)

type ZapLogger struct {
	level  Level //设置打印级别
	logger *zap.Logger
	msgKey string
}

func NewZapLogger(opts ...ZapOption) *ZapLogger {
	l := &ZapLogger{
		level: LevelDebug,
	}

	for _, o := range opts {
		o(l)
	}
	if l.logger == nil {
		//使用默认配置
		l.logger = BuildDefaultLog(l.level, DefaultZapEncoder(), zapcore.AddSync(os.Stdout))
	}

	return l
}

func (z *ZapLogger) Log(level Level, keyvals ...interface{}) error {
	keylen := len(keyvals)
	if keylen == 0 || keylen%2 != 0 {
		z.logger.Warn(fmt.Sprint("Keyvalues must appear in pairs: ", keyvals))
		return nil
	}

	data := make([]zap.Field, 0, (keylen/2)+1)
	for i := 0; i < keylen; i += 2 {
		data = append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i+1]))
	}
	switch level {
	case LevelDebug:
		z.logger.Debug(z.msgKey, data...)
	case LevelInfo:
		z.logger.Info(z.msgKey, data...)
	case LevelWarn:
		z.logger.Warn(z.msgKey, data...)
	case LevelError:
		z.logger.Error(z.msgKey, data...)
	case LevelFatal:
		z.logger.Fatal(z.msgKey, data...)
	}
	return nil
}

func WithLevel(level Level) ZapOption {
	return func(opts *ZapLogger) {
		opts.level = level
	}
}

func WithZapMsgKey(k string) ZapOption {
	return func(opts *ZapLogger) {
		opts.msgKey = k
	}
}

func WithZapLogger(logger *zap.Logger) ZapOption {
	return func(opts *ZapLogger) {
		opts.logger = logger
	}
}

func (l *ZapLogger) Sync() error {
	return l.logger.Sync()
}

func (l *ZapLogger) Close() error {
	return l.Sync()
}

func BuildDefaultLog(level Level, encoder zapcore.Encoder, ws ...zapcore.WriteSyncer) *zap.Logger {
	core := zapcore.NewCore(
		encoder,
		zapcore.NewMultiWriteSyncer(ws...),
		level.ToZapLevel(),
	)
	// 开启开发模式，堆栈跟踪
	caller := zap.AddCaller()
	// 开启文件及行号
	development := zap.Development()
	// 构造日志
	return zap.New(core, caller, development, zap.AddCallerSkip(2))
}

/**
 * 默认编码器
 */
func DefaultZapEncoder() zapcore.Encoder {
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "lineNum",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,                          // 小写编码器
		EncodeTime:     zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000"), // ISO8601 UTC 时间格式
		EncodeDuration: zapcore.SecondsDurationEncoder,                         //
		EncodeCaller:   zapcore.ShortCallerEncoder,                             // 全路径编码器
		EncodeName:     zapcore.FullNameEncoder,
	}
	//zapcore.NewJSONEncoder(encoderConfig),
	return zapcore.NewConsoleEncoder(encoderConfig)
}
